package com.spring.theory.aop.advice;

import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * aop 1-6 调用链的执行
 * <p>
 * aop通知主要使用的是 责任链模式
 * -每个环绕通知内部继续调用 proceed() 方法；调到没有通知后，就调用目标方法
 *
 * @date 2024/1/10 22:43
 */
@Slf4j
public class TestInvocationChain {

    static class Target {
        public void test() {
            log.info("target方法调用");
        }
    }

    static class Advice1 implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            log.info("advice 1 before..");
            Object result = invocation.proceed();
            log.info("advice 1 after..");
            return result;
        }
    }

    static class Advice2 implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            log.info("advice 2 before..");
            Object result = invocation.proceed();
            log.info("advice 2 after..");
            return result;
        }
    }

    //参考 ReflectiveMethodInvocation
    static class MyInvocation implements MethodInvocation {
        private Object target;
        private Method method;
        private Object[] args;
        private List<MethodInterceptor> methodInterceptorList;
        private int count = 1;

        public MyInvocation(Object target, Method method, Object[] args, List<MethodInterceptor> methodInterceptorList) {
            this.target = target;
            this.method = method;
            this.args = args;
            this.methodInterceptorList = methodInterceptorList;
        }

        @Override
        public Method getMethod() {
            return method;
        }

        @Override
        public Object[] getArguments() {
            return args;
        }

        /**
         * 调用每一个环绕通知，调用目标
         */
        @Override
        public Object proceed() throws Throwable {
            // 2.调用目标类
            if (count > methodInterceptorList.size()) {
                return method.invoke(target, args);
            }
            // 1.获取每一个通知并且调用；递归调用通知；每一个通知都是一个责任对象
            MethodInterceptor methodInterceptor = methodInterceptorList.get(count++ - 1);
            return methodInterceptor.invoke(this);
        }

        @Override
        public Object getThis() {
            return target;
        }

        @Override
        public AccessibleObject getStaticPart() {
            return method;
        }
    }

    public static void main(String[] args) throws Throwable {
        Target target = new Target();
        /**
         *  每一个通知都是一个责任人，它们分别有自己的前后逻辑及方法调用
         *  每个责任人都是给目标做增强的，并且管辖在总责任人手下；总责任人一次性收取完责任人的增强后，返回目标，并且依次倒序返回责任人的增强
         */
        List<MethodInterceptor> list = Arrays.asList(new Advice1(), new Advice2());
        MyInvocation invocation = new MyInvocation(target, target.getClass().getMethod("test"), new Object[0], list);
        invocation.proceed();

    }

}
